package org.flexthinker.binding.value.support
{
    import org.flexthinker.binding.value.CommitTrigger;

    import org.hamcrest.assertThat;
    import org.hamcrest.object.equalTo;

    public class BufferedValueModelTest
    {
        private var vh:ValueHolder;
        private var bufferedVM:BufferedValueModel;
        private var mockBean:MockBean;

        private var vhListener:PropertyChangeListenerCounter = new PropertyChangeListenerCounter();
        private var bufferedModelListener:PropertyChangeListenerCounter = new PropertyChangeListenerCounter();

        public function BufferedValueModelTest()
        {
        }

        [Before]
        public function setUp():void
        {
            mockBean = new MockBean();
        }


        [Test]
        public function testThatOnlyBufferModelChanges():void
        {
            vh = new ValueHolder( mockBean, "bindablePropertyWithCustomEvent" );
            //vh.setValue("HELLO BUFFER");
            mockBean.bindablePropertyWithCustomEvent = "HELLO BUFFER";
            bufferedVM = new BufferedValueModel( vh );

            assertThat( "both valueHolder and bufferdValueModel should have same values initially", vh.getValue(),
                        equalTo( bufferedVM.getValue() ) );
            assertThat( "BufferedValueModel has the wrong value", bufferedVM.getValue(),
                        equalTo( mockBean.bindablePropertyWithCustomEvent ) );

            vh.addValueChangeListener( vhListener );
            bufferedVM.addValueChangeListener( bufferedModelListener );

            bufferedVM.setValue( "BUFFERED" );
            assertThat( "Buffered Model Listener should have been called", bufferedModelListener.counter, equalTo( 1 ) );
            assertThat( "ValueHolder's listener shouldn't be called now.", vhListener.counter, equalTo( 0 ) );
            assertThat( "ValueHolder should have not been updated.", vh.getValue(), equalTo( "HELLO BUFFER" ) );
            assertThat( "BufferedValueModel should have been updated.", bufferedVM.getValue(), equalTo( "BUFFERED" ) );
            assertThat( "MockBean should have not been updated.", mockBean.bindablePropertyWithCustomEvent, equalTo( vh.getValue() ) );
        }

        [Test]
        public function testThatCommitUpdatesTheWrappedModel():void
        {
            vh = new ValueHolder( mockBean, "bindablePropertyWithCustomEvent" );
            vh.setValue( "HELLO BUFFER" );
            bufferedVM = new BufferedValueModel( vh );

            vh.addValueChangeListener( vhListener );
            bufferedVM.addValueChangeListener( bufferedModelListener );

            assertThat( "BufferedValueModel should NOT be buffering b/c there are NO changes", bufferedVM.isBuffering(), equalTo( false ) );
            bufferedVM.setValue( "BUFFERED" );
            assertThat( "BufferedValueModel should be buffering b/c there are changes", bufferedVM.isBuffering(), equalTo( true ) );

            bufferedVM.setValue( "HELLO BUFFER" );
            assertThat( "BufferedValueModel should NOT be buffering since the value has been set back", bufferedVM.isBuffering(),
                        equalTo( false ) );

            bufferedVM.setValue( "BUFFERED AGAIN" );
            assertThat( "Listener for ValueHolder shouldn't have been called", vhListener.counter, equalTo( 0 ) );
            bufferedVM.commit();
            assertThat( "Wrong behavior in listener of buffered value model", bufferedModelListener.counter, equalTo( 3 ) );
            assertThat( "Listener for ValueHolder should be called after commit", vhListener.counter, equalTo( 1 ) );
            assertThat( "ValueHolder should have the new value after commit", vh.getValue(), equalTo( bufferedVM.getValue() ) );
            assertThat("MockBean should also be changed after commit", mockBean.bindablePropertyWithCustomEvent, equalTo( bufferedVM.getValue() ));
            assertThat("BufferedValueModel shouldn't be buffering after commit", bufferedVM.isBuffering(), equalTo(false));

        }

        [Test]
        public function testThatRevertWorksAsExpected():void
        {
            vh = new ValueHolder( mockBean, "bindablePropertyWithCustomEvent" );
            vh.setValue( "HELLO BUFFER" );
            bufferedVM = new BufferedValueModel( vh );

            vh.addValueChangeListener( vhListener );
            bufferedVM.addValueChangeListener( bufferedModelListener );

            bufferedVM.setValue("TEMPORARY VALUE");
            bufferedVM.setValue("TEMP VAL2");
            bufferedVM.setValue("temp val 3");

            assertThat("Buffered listener should have been called", bufferedModelListener.counter, equalTo(3));
            bufferedVM.revert();
            assertThat("BufferedModel should have been reverted to original", bufferedVM.getValue(), equalTo(vh.getValue()));
            assertThat("Buffered listener should have been called on revert() too", bufferedModelListener.counter, equalTo(4));

        }

        [Test]
        public function testBufferModelUpdatesWhenBeanUpdates():void
        {
            vh = new ValueHolder( mockBean, "bindablePropertyWithCustomEvent" );
            vh.setValue( "HELLO BUFFER" );
            bufferedVM = new BufferedValueModel( vh );

            vh.addValueChangeListener( vhListener );
            bufferedVM.addValueChangeListener( bufferedModelListener );

            bufferedVM.setValue("temp val");
            
            mockBean.bindablePropertyWithCustomEvent = "NEW VAL";

            assertThat("BufferedModel should reset according to the changes in the bean", bufferedVM.getValue(), equalTo(mockBean.bindablePropertyWithCustomEvent));
            assertThat("BufferedModel shouldn't be dirty", bufferedVM.isBuffering(), equalTo(false));
        }

        [Test]
        public function testCommitTriggerWithBufferedValueModel():void
        {
            var commitTrigger:CommitTrigger = new CommitTrigger();
            vh = new ValueHolder( mockBean, "bindablePropertyWithCustomEvent" );
            vh.setValue( "HELLO BUFFER" );
            bufferedVM = new BufferedValueModel( vh );


            bufferedVM.setCommitTrigger( commitTrigger );

            vh.addValueChangeListener( vhListener );
            bufferedVM.addValueChangeListener( bufferedModelListener );

            bufferedVM.setValue("TEMPORARY VALUE");
            bufferedVM.setValue("TEMP VAL2");
            bufferedVM.setValue("temp val 3");

            assertThat("Buffered listener should have been called", bufferedModelListener.counter, equalTo(3));
            commitTrigger.revert();
            assertThat("BufferedModel should have been reverted to original", bufferedVM.getValue(), equalTo(vh.getValue()));
            assertThat("Buffered listener should have been called on revert() too", bufferedModelListener.counter, equalTo(4));
            assertThat("BufferedValueModel shouldn't be buffering after revert", bufferedVM.isBuffering(), equalTo(false));

        }
    }
}